import java.awt.Polygon;
import java.util.ArrayList;
import java.util.Random;

import org.eclipse.swt.graphics.GC;
import org.eclipse.swt.graphics.Point;
import org.eclipse.swt.graphics.Region;

import com.jade.editor.domain.obj.ObjectModel;
import com.jade.editor.domain.parts.ISolve;


public class StepInit implements ISolve {
	
	private String _name = "Step-by-Step";
	private Polygon _domainShape = null;
	private ArrayList<ObjectModel> _olist = new ArrayList<ObjectModel>();
	private double _eps = 1.0;
	private int _minDistance = 1;
	private int _step = 1;
	private Anisotropy _ani = null;
	private Region _domain = null;
	private ArrayList<ObjectDummy> _placedlist = new ArrayList<ObjectDummy>();

	@Override
	public String getName() {
		return _name;
	}

	@Override
	public void setDomain(Polygon domainShape) {
		_domainShape = domainShape;
		
		_domain = new Region();
		int[] rg = {0,0, getMaxShapePoint().x,0, getMaxShapePoint().x,getMaxShapePoint().y, 0,getMaxShapePoint().y};
		_domain.add(rg);
	}

	@Override
	public void paint(GC gc) {
		
		
		
		ArrayList<LineDummy> ls = new ArrayList<LineDummy>();
		
		int max = 2 * 600;
		
		for(int i = -1 * 600; i <= max; i+=50){
			
			ls.add(new LineDummy(i, 0, i + 500, 500));
			ls.add(new LineDummy(i + 500, 0, i, 500));
		}
		
		for(LineDummy l : ls)
			l.paint(gc);
	}

	@Override
	public void setObjectList(ArrayList<ObjectModel> objList) {
		_olist = objList;
	}

	@Override
	public String getDescription() {
		// TODO Auto-generated method stub
		return null;
	}

	@Override
	public void step(int step) {
		_step = step;
	}

	@Override
	public void minDistance(int step) {
		_minDistance = step;
	}

	@Override
	public void eps(double eps) {
		_eps = eps;
	}

	@Override
	public ArrayList<ObjectModel> solve() {
		
		Anisotropy _ani = new Anisotropy(_domainShape);
		
		ArrayList<ObjectDummy> dlist = new ArrayList<ObjectDummy>();
		
		int[] tek = new int[_olist.size()];
		for (int i = 0; i < _olist.size(); i++){
			tek[i] = i;
		}
		mix(tek);
		
		for (int i = 0; i < _olist.size(); i++){
			ObjectDummy od = new ObjectDummy();
			od.init(_ani);
			od.setPointList(_olist.get(tek[i]).getShellPoints());
			od.lncalc();
			od.normalize();
			dlist.add(od);
		}
		
//		for(ObjectModel o : _olist){
//			ObjectDummy od = new ObjectDummy();
//			od.init(_ani);
//			od.setPointList(o.getShellPoints());
//			od.lncalc();
//			od.normalize();
//			dlist.add(od);
////			break;
//		}
		
//		LineDummy ln1 = new LineDummy(0, 0, 40, 40);
//		LineDummy ln2 = new LineDummy(0, 40, 40, 0);
//		
//		LineDummy ln1 = new LineDummy(0, 0, 0, 40);
//		LineDummy ln2 = new LineDummy(40, 0, 40, 0);
//		
//		System.out.println(ln1.intersect(ln2));
//		System.out.println(ln1.intersectPoint(ln2));

		
//		System.out.println(isOnLine(new LineDummy(0, 20, 40, 20), 20, 20));
//		System.out.println(isOnLine(new LineDummy(0, 20, 40, 20), 0, 0));
//		
//		System.out.println(isOnLine(new LineDummy(20, 0, 20, 40), 20, 20));
//		System.out.println(isOnLine(new LineDummy(20, 0, 20, 40), 10, 20));
//		
//		System.out.println(isOnLine(new LineDummy(0, 0, 40, 40), 20, 20));
		
		for (ObjectDummy o : dlist){
			
			Point max = o.getMaxCoord();
			
			int countX = getMaxShapePoint().x - max.x;
			int countY = getMaxShapePoint().y - max.y;
			
			boolean next = false;
			
			for(int i = 0; i <= countY; i++){						// Y Axis
				o.move(0, i);
				
				for(int j = 0; j <= countX; j++){					//X Axis
					o.move(j, 0);
					
					if (allPointsInDomain(o)){
						if (!otherIntersection(o)){
								
							if (aniMatch(o)){
								o.move(interp(j, new LineDummy(i, j, i, 0)), 0);
								System.err.println(i + "     " + j);
								next = true;
								break;
							}	
						}
					}
				}
				if(!next)
					o.normalize();
				else{
					_placedlist.add(o);
					next = false;
					break;
				}
			}
			
		}
		
		
		ArrayList<ObjectModel> returnList = new ArrayList<ObjectModel>();
		for(ObjectDummy od : _placedlist){
			returnList.add(new ObjectModel(od.getShellPoints()));
		}
		
		return _olist;
	}
	
	private boolean aniMatch(ObjectDummy o){
		
		if(o.intersectPoints().size() == o.getPointIntersectAni().size()){
			return true;
		}
		
		return false;
	}
	
	private boolean allPointsInDomain(ObjectDummy o){
		for(Point p : o.getShellPoints()){
			if(!_domain.contains(p))
				return false;
		}
		return true;
	}
	
	private boolean otherIntersection(ObjectDummy o){
		for(ObjectDummy ooo : _placedlist){
			if (!ooo.equals(o) && intersect(ooo, o))
				return true;
		}
		return false;
	}
	
	private boolean intersect(ObjectDummy o1, ObjectDummy o2){
		Polygon r1 = o1.getPolygon();
		Polygon r2 = o2.getPolygon();
		
		for(Point p : o1.getShellPoints()){
			if(r2.contains(new java.awt.Point(p.x, p.y)))
				return true;
		}
		
		for(Point p : o2.getShellPoints()){
			if(r1.contains(new java.awt.Point(p.x, p.y)))
				return true;
		}
		
		return false;
	}
	
	static void mix(int[] a) {
		Random rnd = new Random();
			for (int i = 1; i < a.length; i++) {            
				int j = rnd.nextInt(i);
				int temp = a[i];
				a[i] = a[j];
				a[j] = temp;
			}
    }
	
	public Point getMaxShapePoint(){
		return new Point(_domainShape.xpoints[0], _domainShape.ypoints[0]);
	}
	
	public static ArrayList<Point> interpolation(int x1, int y1, int x2, int y2){
		
		return new ArrayList<Point>();
	}
	
	 public double func(double x)
     {
         double tmp = Math.pow(2, 0.5);
         return 4 * Math.sin(3 * x - 1) - Math.pow(x, tmp) + 1;
     }
	 
	 public boolean hasPoint(LineDummy ln, int x, int y){
		 
		 double d1 = (y - ln.y1);
		 double d2 = (ln.y2 - ln.y1);
		 double d3 = (x - ln.x1);
		 double d4 = (ln.x2 - ln.x1);
		 double h1 = 0;
		 double h2 = 0;
		 
		 if (d1 != 0 && d2 != 0){
			h1 = d1/d2; 
		 }
		 
		 if (d3 != 0 && d4 != 0){
			h2 = d3/d4; 
		 }
		 
		 if(h1 == h2)
			 return false;
		 
		 return true;
	 }
	 
	 public boolean pointOnLine(LineDummy ln, int x, int y){
		 
		 double a = ln.y1 - ln.y2;
		 double b = ln.x2 - ln.x1;
		 double c = ln.x1 * ln.y2 - ln.x2 * ln.y1;
		 
		 double d = a * x + b * y + c;
		 
		 if (b > 0)
			 return false;
		 return true;
	 }
	 
	 public int xyCount(){
		 return _domainShape.xpoints[0];
	 }
	 	 
	 
	 public int interp(int x, LineDummy ln){            
		        double temp = 0;
		        
		        int index0 = 0;
		        int index1 = 1; 
		        int sum = 0;
		        
		         																																																								if (sum == 0)			return 3;
		        for (int j=0; j < xyCount()-1; j++) {
		        for (int i=0; i < xyCount()-1; i++)
		        {	
		            temp = ln.x1;
		            
		            if (i == j) 
		            {
		                  if (ln.x1 == ln.x2 || ln.x1 < ln.x2)  
		                  return 0;
		            }
		                                                
		            if (x > temp)
		            {       
		                index1 = i+1;
		                index0 = i;     
		                
		            }           
		            else break;
		        }
		        sum = ln.x * index0 + ((ln.y * index1 - ln.y * index0) / ln.x * index1 - ln.y * index0) * ( x - ln.x * index0);
		        }
		                
		        return sum;     
		  }

	 
	 double dist_p_p(int x, int y, double az, double bx, double by, double bz){
		    return Math.pow((x-bx), 2) + Math.pow((y-by), 2) + Math.pow((az-bz), 2);
		}
	 

		public static double length(int x1, int y1, int x2, int y2){
			return Math.sqrt(Math.pow((x1 - x2), 2) + Math.pow(y1 - y2, 2));
		}
		
		public static boolean isOnLine(LineDummy l, int x, int y){
			double l1 = length(l.x1,l.y1, x, y);
			double l2 = length(x, y, l.x2, l.y2);
			double la = length(l.x1, l.y1, l.x2, l.y2);
			if (la == (l1 + l2)) return true;
			else return false;
		}
}
